package com.spring.demo8.eg1;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.*;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

/**
 * @author vhans
 */
public class Test {
    @org.junit.Test
    public void test() {
        // 通过BeanDefinitionBuilder工具类组装一个Car类型的简单bean
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        // 获取BeanDefinition
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(beanDefinition);
    }

    @org.junit.Test
    public void test1() {
        // 通过BeanDefinitionBuilder工具类组装一个Car类型的有属性的bean
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName());
        // 设置普通属性
        beanDefinitionBuilder.addPropertyValue("name", "宝马");
        // 获取BeanDefinition
        AbstractBeanDefinition carBeanDefinition = beanDefinitionBuilder.getBeanDefinition();
        System.out.println(carBeanDefinition);

        // 创建spring容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //调用registerBeanDefinition向容器中注册bean
        factory.registerBeanDefinition("car", carBeanDefinition);
        // 查看
        System.out.println(factory.getBean("car", Car.class));
    }

    @org.junit.Test
    public void test2() {
        // 组装一个有依赖关系的bean
        // 先创建一个Car的带参bean定义
        BeanDefinition carBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Car.class.getName())
                .addPropertyValue("name", "宝马")
                .getBeanDefinition();
        // 创建User的beanDefinition
        BeanDefinition userBeanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class.getName())
                .addPropertyValue("name", "Vhans")
                .addPropertyReference("car", "car")     // 使用addPropertyReference来注入依赖的bean
                .getBeanDefinition();

        // 创建spring容器并注册car和user
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("car", carBeanDefinition);
        factory.registerBeanDefinition("user", userBeanDefinition);

        System.out.println(factory.getBean("car"));
        System.out.println(factory.getBean("user"));
    }

    @org.junit.Test
    public void test3() {
        // 组装有父子关系的bean
        AbstractBeanDefinition carBeanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition(Car.class)
                .addPropertyValue("name", "宝马")
                .getBeanDefinition();
        AbstractBeanDefinition carBeanDefinition2 = BeanDefinitionBuilder.genericBeanDefinition()
                .setParentName("car1")  // 设置父bean名称
                .getBeanDefinition();

        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("car1", carBeanDefinition1);
        factory.registerBeanDefinition("car2", carBeanDefinition2);

        System.out.println("car1->" + factory.getBean("car1"));
        System.out.println("car2->" + factory.getBean("car2"));
    }

    @org.junit.Test
    public void test4() {
        // 纯Api方式实现CompositeObj的组装
        // 定义car1
        AbstractBeanDefinition car1BeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Car.class)
                .addPropertyValue("name", "宝马")
                .getBeanDefinition();
        // 定义car2
        AbstractBeanDefinition car2BeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Car.class)
                .addPropertyValue("name", "保时捷")
                .getBeanDefinition();

        // 以下定义compositeObj
        // 创建stringList
        ManagedList<String> stringList = new ManagedList<>();
        stringList.addAll(Arrays.asList("spring", "spring boot", "spring cloud"));

        // 创建carList
        ManagedList<RuntimeBeanReference> carList = new ManagedList<>();
        carList.add(new RuntimeBeanReference("car1"));  //RuntimeBeanReference:表示bean应用类型，类似xml中的ref
        carList.add(new RuntimeBeanReference("car2"));

        // 创建stringSet
        ManagedSet<String> stringSet = new ManagedSet<>();  // ManagedList:属性如果是List类型的，需要用到这个类进行操作，这个类继承了ArrayList
        stringSet.addAll(Arrays.asList("spring", "spring boot", "spring cloud"));

        // 创建carSet
        ManagedSet<RuntimeBeanReference> carSet = new ManagedSet<>();   // ManagedSet:属性如果是Set类型的，需要用到这个类进行操作，这个类继承了LinkedHashSet
        carSet.add(new RuntimeBeanReference("car1"));
        carSet.add(new RuntimeBeanReference("car2"));

        // 创建stringMap
        ManagedMap<String, String> stringMap = new ManagedMap<>();  // ManagedMap:属性如果是Map类型的，需要用到这个类进行操作，这个类继承了LinkedHashMap
        stringMap.put("学习1", "spring");
        stringMap.put("学习2", "spring boot");
        stringMap.put("学习3", "spring cloud");

        // 创建carMap
        ManagedMap<String, RuntimeBeanReference> carMap = new ManagedMap<>();
        carMap.put("car1", new RuntimeBeanReference("car1"));
        carMap.put("car2", new RuntimeBeanReference("car2"));

        // 开始使用原生Api组装compositeObj
        GenericBeanDefinition compositeObj = new GenericBeanDefinition();
        compositeObj.setBeanClassName(CompositeObj.class.getName());
        compositeObj.getPropertyValues()
                .add("name", "Vhans")
                .add("salary", 20000)
                .add("car1", new RuntimeBeanReference("car1"))
                .add("stringList", stringList)
                .add("carList", carList)
                .add("stringSet", stringSet)
                .add("carSet", carSet)
                .add("stringMap", stringMap)
                .add("carMap", carMap);

        // 将上面的bean注册到容器
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        factory.registerBeanDefinition("car1", car1BeanDefinition);
        factory.registerBeanDefinition("car2", car2BeanDefinition);
        factory.registerBeanDefinition("compositeObj", compositeObj);

        for (String beanName : factory.getBeanDefinitionNames()) {
            System.out.println(beanName + "->" + factory.getBean(beanName));
        }
    }

    @org.junit.Test
    public void test5() {
        // 通过xml方式组装compositeObj，与test4效果一样
        String beanXml = "classpath:/xml/demo8/compositeObj.xml";
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
        for (String beanName : context.getBeanDefinitionNames()) {
            System.out.println(beanName + "->" + context.getBean(beanName));
        }
    }
}
